//Global variables
var objMain;
var objLastline;
var objLine;
var objPS1;
var objLog;

var arrCommands = [];
var historyPointer;
var curLineBuffer;

var arrAutocomplete;
var autocompletePointer;

//Constants
var HISTORYSIZE = 100;
var HELLOMSG = '<span class="green">Welcome to Kai6\'s web terminal</span>' +
'\nWebsite: <a class="red" href="http://kjwon15.netii.net/">kjwon15.netii.net</a>' +
'\nBlog: <a class="red" href="http://kjwon15.tistory.com/">kjwon15.tistory.com</a>';
var PS1 = '<span class="red">|ID|</span>@<span class="blue">|HOST|</span>:<span class="yellow">|PWD|</span>$'

function init_terminal(){
	objMain = document.querySelector("#main");
	objLastline = document.querySelector("#lastline");
	objLine = document.querySelector("#line");
	objPS1 = document.querySelector("#PS1");
	objLog = document.querySelector("#log");


	print(HELLOMSG);
	ParsePS1();
	objLine.value = '';

	document.body.addEventListener('click', function(){objLine.focus();}, false);
	//Return key
	objLine.addEventListener('keydown', keypressHandler, false);

	objMain.style.opacity = 1.0;

	objLine.focus();
}

function keypressHandler(event){
	if(event.keyCode == 0x0d){ // return
		event.preventDefault();
		var commandLine = objLine.value;

		//add history
		if(commandLine.trim().length > 0){
			arrCommands.push(commandLine);
		}
		if(arrCommands.length > HISTORYSIZE){
			arrCommands.shift(arrCommands.length - HISTORYSIZE);
		}

		//hide lastline
		objLastline.style.display = 'none';

		//line to log
		print(objPS1.innerHTML + objLine.value);
		objLine.value = "";

		ParseCommand(commandLine);

		ParsePS1();

		//show lastline
		objLastline.style.display = 'block';
		objLine.focus();
		//set history pointer to final
		historyPointer = arrCommands.length;

		//scroll to bottom
		objMain.scrollTop = objMain.scrollHeight;
	}else if(event.keyCode == 0x26){ //up arrow
		event.preventDefault();
		if(historyPointer == arrCommands.length){ //last line
			curLineBuffer = objLine.value;
		}
		if(historyPointer > 0){
			objLine.value = arrCommands[--historyPointer];
		}
	}else if(event.keyCode == 0x28){ //down arrow
		event.preventDefault();
		if(historyPointer < arrCommands.length - 1){
			objLine.value = arrCommands[++historyPointer];
		}else if(historyPointer == arrCommands.length - 1){ //load curBuffer
			objLine.value = curLineBuffer;
			historyPointer = arrCommands.length;
		}
	}else if(event.keyCode == 0x09){ //tab key
		event.preventDefault();
		if(arrAutocomplete != null){
			autocompletePointer = (autocompletePointer+1)%arrAutocomplete.length;
			objLine.value = arrAutocomplete[autocompletePointer];
		}else{
			var cmdline = objLine.value;
			var index = cmdline.lastIndexOf(' ');
			var prev = cmdline.slice(0, index + 1);
			var toComplete = cmdline.slice(index+1);

			var arr = CURDIR.getAutocomplete(toComplete);
			if(arr != null){
				if(arr.length == 1){
					objLine.value = prev + arr[0];
				}else{
					arrAutocomplete = arr.map(function(complete){
						return prev + complete;
					});
					console.log(arrAutocomplete);
					autocompletePointer = 0;
					objLine.value = prev + arr[0];
				}
			}else{
				objLine.value = objLine.value;
			}
		}
	}else{
		arrAutocomplete = null;
		autocompletePointer = 0;
	}
}

function ParsePS1(){
	objPS1.innerHTML = PS1.replace('|ID|', 'guest')
		.replace('|HOST|', 'kai6')
		.replace('|PWD|', CURDIR.getPath());
}

function print(string){
	var temp = document.createElement('pre');
	temp.innerHTML = string;
	objLog.appendChild(temp);
}

function sleep(ms){
	var to = Date.now() + ms;
	while(Date.now() < to);
}

function ParseCommand(command){
	var States = {
		normal: 'normal',
		whitespace: 'whitespace',
		backslash: 'backslash',
		quote: 'quote',
		singlequote: 'singlequote'
	};
	var state = States.normal;
	var prevstate = state; // for backslash mode

	var args = [];
	var buffer = "";
	for(var i=0; i<command.length; i++){
		var input = command[i];
		switch(state){
			case States.normal:
				switch(input){
					case '\\':
						prevstate = state;
						state = States.backslash;
						break;
					case '\"':
						state = States.quote;
						break;
					case '\'':
						state = States.singlequote;
						break;
					case ' ':
						state = States.whitespace;
						args.push(buffer);
						buffer = "";
						break;
					default:
						buffer += input;
				}
				break;
			case States.whitespace:
				switch(input){
					case ' ':
						break;
					case '\\':
						//new character. same as default
						prevstate = States.normal;
						state = States.backslash;
						break;
					case '\"':
						state = States.quote;
						break;
					case '\'':
						state = States.singlequote;
						break;
					default:
						buffer += input;
						state = States.normal;
				}
				break;
			case States.backslash:
				buffer += input;
				state = prevstate;
				break;
			case States.quote:
				switch(input){
					case '\"':
						state = States.normal;
						break;
					case '\\':
						prevstate = state;
						state = States.backslash;
						break;
					default:
						buffer += input;
				}
				break;
			case States.singlequote:
				switch(input){
					case '\'':
						state = States.normal;
						break;
					case '\\':
						prevstate = state;
						state = States.backslash;
						break;
					default:
						buffer += input;
				}
				break;
		}
	}
	if(state == States.normal || state == States.whitespace){
		if(buffer.length > 0){
			args.push(buffer);
		}
		DoCommand(args);
	}else{
		print("Command line parse error");
	}
}

function DoCommand(args){
	if(args.length == 0){
		return;
	}else{
		switch(args[0]){
			case 'help':
				print("help: show this message");
				print("echo: echo program");
				print("clear: clear screen");
				print("history: show command history");
				print("pwd: show current working directory");
				print("cd: change working directory");
				print("ls: show current/specific directory");
				print("cat: show file contents");
				break;
			case 'clear':
				objLog.innerHTML = "";
				break;
			case 'history':
				print(arrCommands.join('\n'));
				break;
			case 'echo':
				print(args.slice(1).join(' '));
				break;
			case 'pwd':
				print(CURDIR.getPath());
				break;
			case 'cd':
				if(args[1] == undefined){
					print("Usage: cd &lt;destination&gt;");
					return;
				}
				var destination = CURDIR.getDir(args[1]);
				if(destination == null){
					print("directory not found");
				}else if(destination.type != 'directory' && destination.type != 'specialdirectory'){
					print("Not a directory");
				}else{
					if(destination.type == 'specialdirectory'){
						objMain.style.opacity = 0.0;
						location.href = destination.dest;
					}else{
						CURDIR = destination;
					}
				}
				break;
			case 'ls':
				//TODO: parse -a, -l
				var option_hidden = false;
				var option_verbose = false;
				var option_destination = null;
				var result = null;

				for(var i=1; i<args.length; i++){
					if(args[i][0] == '-'){
						if(args[i].indexOf('a') > -1){
							option_hidden = true;
						}
						if(args[i].indexOf('l') > -1){
							option_verbose = true;
						}
					}else{
						option_destination = args[i];
					}
				}

				if(option_destination){
					var dest =  CURDIR.getDir(option_destination);
					if(dest == null){
						print("directory not found");
						return;
					}else{
						if(dest.type == 'directory'){
							result = dest.getChild(option_hidden);
						}else{
							result = [dest];
						}
					}
				}else{
					result = CURDIR.getChild(option_hidden);
				}
				if(option_verbose == false){
					var output = result.map(function(obj){
						switch(obj.type){
							case 'directory':
								return '<span class="blue">'+obj.name+'</span>';
								break;
							case 'specialdirectory':
								return '<span class="yellow">'+obj.name+'</span>';
								break;
							case 'program':
								return '<span class="green">'+obj.name+'</span>';
								break;
							case 'file':
								return obj.name;
								break;
						}
					}).join(' ');
					print(output);
				}else{
					var output = result.map(function(obj){
						switch(obj.type){
							case 'directory':
								return 'drw-rw-rw- <span class="blue">'+obj.name+'</span>\t'+obj.getSize();
								break;
							case 'specialdirectory':
								return 'srw-rw-rw- <span class="yellow">'+obj.name+'</span>\t'+obj.getSize();
								break;
							case 'program':
								return '-rwxrwxrwx <span class="green">'+obj.name+'</span> '+obj.getSize();
								break;
							case 'file':
								return '-rw-rw-rw- ' + obj.name+' '+obj.getSize();
								break;
						}
					}).join('\n');
					print(output);
				}
				break;
			case 'cat':
				if(args[1] == undefined){
					print("Usage: cat &lt;file&gt;");
					return;
				}
				var file = CURDIR.getDir(args[1]);
				if(file == null){
					print(args[1] + ": File not found");
				}else if(file.type != 'file'){
					print(args[1] + ": Not a file");
				}else{
					print(file.content);
				}
				break;
			default:
				var program = CURDIR.getDir(args[0]);
				if(program != null && program.type=='program'){
					args[0] = args[0].slice(args[0].lastIndexOf('/')+1);
					program.execute(args);
				}else{
					print(args[0] + ": command not found");
				}
		}
	}
}
